package com.charlie.api.client.translator;

import com.charlie.api.client.config.DefaultThreadPoolConfig;
import com.charlie.api.client.config.RegTranslateConfig;
import com.charlie.api.client.exception.BusinessException;
import com.charlie.api.client.exception.ErrorCode;
import com.charlie.api.client.model.dto.RegexDTO;
import freemarker.cache.ClassTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;


/**
 * @program: regex-translation
 * @description:
 * @author: Charlie
 * @create: 2024-01-16 12:23
 **/
public abstract class AbstractTranslator implements Translator {

    protected static Configuration configuration;

    static {
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
        cfg.setTemplateLoader(new ClassTemplateLoader(AbstractTranslator.class, "/templates"));
        cfg.setDefaultEncoding("UTF-8");
        cfg.setLogTemplateExceptions(false);
        cfg.setWrapUncheckedExceptions(true);
        configuration = cfg;
    }

    @Override
    public final Map<String, String> translate(List<String> regexList, String templateName, RegTranslateConfig config) {
        //1. 获取模版
        Template template = getTemplate(templateName);
        if (template == null) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "not found template");
        }
        if (!config.getIsParallel()) {
            Map<String, String> map = new HashMap<>(regexList.size());
            for (String regex : regexList) {
                //2. 处理正则
                process(map, regex, template);
            }
            return map;
        } else {
            ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(regexList.size());
            ThreadPoolExecutor executor = config.getExecutor();
            if (executor == null) {
                executor = DefaultThreadPoolConfig.createRegexTranslateExecutor();
            }
            List<Future<?>> futures = new ArrayList<>();
            for (String regex : regexList) {
                Future<?> future = executor.submit(() -> {
                    process(map, regex, template);
                });
                futures.add(future);
            }
            for (Future<?> future : futures) {
                try {
                    future.get();
                } catch (InterruptedException | ExecutionException e) {
                    Thread.currentThread().interrupt();
                }
            }
            executor.shutdown();
            return map;
        }
    }


    /**
     * 对单个正则的预处理方式，模版方法模式由子类扩展实现
     *
     * @param regex 正则
     * @return 模板填充类
     */
    abstract RegexDTO processRegex(String regex);


    /**
     * 获取正则翻译模板
     *
     * @param templateName 模板文件名
     * @return 模板
     */
    private Template getTemplate(String templateName) {
        try {
            return configuration.getTemplate(templateName);
        } catch (IOException e) {
            return null;
        }
    }

    private void process(Map<String, String> map, String regex, Template template) {
        if (!map.containsKey(regex)) {
            RegexDTO regexDTO = processRegex(regex);
            StringWriter sw = new StringWriter();
            try {
                //3.填充
                template.process(regexDTO, sw);
            } catch (TemplateException | IOException e) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "process template error");
            }
            map.put(regex, sw.toString());
        }
    }


}
